package com.lcxw.hxzbapi.controller.roomcontroller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lcxw.hxzbapi.controller.membercontroller.MemberRealization;
import com.lcxw.hxzbapi.entity.pojo.Duanwei;
import com.lcxw.hxzbapi.entity.pojo.Gift;
import com.lcxw.hxzbapi.entity.pojo.RichLevel;
import com.lcxw.hxzbapi.entity.pojo.RoomRank;
import com.lcxw.hxzbapi.entity.pojo.VipLevel;
import com.lcxw.hxzbapi.entity.response.Response;
import com.lcxw.hxzbapi.service.GiftService;
import com.lcxw.hxzbapi.tencentim.common.ImCommand;
import com.lcxw.hxzbapi.tencentim.common.TencentImRealization;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import javax.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import com.lcxw.hxzbapi.entity.pojo.GiftSend;
import com.lcxw.hxzbapi.entity.pojo.YwpdMember;
import com.lcxw.hxzbapi.entity.pojo.YwpdRoom;
import com.lcxw.hxzbapi.service.AttentionService;
import com.lcxw.hxzbapi.service.GiftSendService;
import com.lcxw.hxzbapi.service.YwpdMemberService;
import com.lcxw.hxzbapi.service.YwpdRoomService;
import com.lcxw.hxzbcommon.common.RedisUtils;
import com.lcxw.hxzbcommon.common.RoomUtils;
import com.lcxw.hxzbcommon.common.StringUtil;
import com.lcxw.hxzbcommon.common.qiniu.Client;
import com.lcxw.hxzbcommon.common.qiniu.RoomConfig;
import com.lcxw.hxzbcommon.common.qiniu.Hub;

@Component
@Slf4j
public class RoomRealization {

    @Resource
    GiftSendService giftSendService;

    @Resource
    YwpdRoomService ywpdRoomService;

    @Resource
    YwpdMemberService ywpdMemberService;

    @Resource
    MemberRealization memberRealization;

    @Resource
    AttentionService attentionService;

    @Resource
    RedisUtils redisUtils;

    @Resource
    GiftService giftService;

    @Resource
    TencentImRealization tencentImRealization;

    @Resource
    Qiniu qiniu;

    /**
     * 获取房间打赏榜单的信息
     */
    public List<Object> getReward(long roomId) throws Exception {

//        long userId = ywpdRoomService.selectRoomByRoomId(roomId).getUserId();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date zero = calendar.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String addTime = sdf.format(zero);

        List<GiftSend> giftSends = giftSendService.selectCurrentDayByRoomId(roomId, addTime);

        if (null == giftSends) {
            return null;
        }

        Map<Long, Integer> rewardMap = new TreeMap<>();

        for (GiftSend giftSend : giftSends) {
            long fromUserId = giftSend.getFromUserId();
            int giftNum = giftSend.getGiftNum();
            int needCoin = giftSend.getNeedCoin();

            if (rewardMap.containsKey(fromUserId)) {
                int count = rewardMap.get(fromUserId);
                count += giftNum * needCoin;
                rewardMap.put(fromUserId, count);
            } else {
                rewardMap.put(fromUserId, giftNum * needCoin);
            }
        }
        Map<?, Integer> rewards = StringUtil.mapSortByValue(rewardMap);

        List<Object> rewardList = new ArrayList<>();

        Set<?> objects = rewards.keySet();

        Iterator<?> iterator = objects.iterator();
        while (iterator.hasNext()) {
            long fromUserId = (Long) iterator.next();
            Reward reward = new Reward();
            YwpdMember ywpdMember = ywpdMemberService.selectYwpdMemberByUserId(fromUserId);
            if (null != ywpdMember) {
                reward.put("userId", fromUserId);
                reward.put("nickName", ywpdMember.getNickName());
                reward.put("imgUrl", ywpdMember.getImgUrl());
                reward.put("age", ywpdMember.getAge());
                reward.put("sex", ywpdMember.getSex());
                reward.put("contribution", rewards.get(fromUserId) * 10);//贡献值，即火力值，赠送礼物的总价值*10

                Map levels = memberRealization.getLevels(fromUserId);
                RichLevel richLevel = (RichLevel) levels.get("richLevel");
                VipLevel vipLevel = (VipLevel) levels.get("vipLevel");
                Duanwei duanwei = (Duanwei) levels.get("duanwei");

                if (null != richLevel && null != vipLevel && null != duanwei) {
                    reward.put("richLevel", richLevel.getPicUrl());
                    reward.put("vipLevel", vipLevel.getPicUrl());
                    reward.put("duanwei", duanwei.getPicUrl());
                }
                rewardList.add(reward);
            }
        }
        return rewardList;
    }

    /**
     * redis中存入房间的观众
     */
    public void redisAddViewers(long roomId, long userId) {

        String roomViewer_redisKey = RoomUtils.get_roomViewer_redisKey(roomId);
        String roomViewer_redisValue = userId + "";

        redisUtils.set_add(roomViewer_redisKey, roomViewer_redisValue);


    }

    /**
     * redis中删除房间的一个观众
     */
    public void redisDeleteViewer(long roomId, long userId) {
        String roomViewer_redisKey = RoomUtils.get_roomViewer_redisKey(roomId);
        String roomViewer_redisValue = userId + "";

        redisUtils.set_remove(roomViewer_redisKey, roomViewer_redisValue);
    }

    /**
     * 主持人退播后，删除redis中的观众集合
     */
    public void redisDeleteRoom(long roomId) {
        String roomViewer_redisKey = RoomUtils.get_roomViewer_redisKey(roomId);
        redisUtils.string_delete(roomViewer_redisKey);
    }

    /**
     * 获取关注房间的房间信息
     */
    public List<JSONObject> getAttRoomInfo(List<Long> attRoomIdList) {
        List<JSONObject> data = new ArrayList<>();

        for (long roomId : attRoomIdList) {
            YwpdRoom ywpdRoom;
            YwpdMember ywpdMember;
            try {
                ywpdRoom = ywpdRoomService.selectRoomByRoomId(roomId);
                long userId = ywpdRoom.getUserId();
                ywpdMember = ywpdMemberService.selectYwpdMemberByUserId(userId);
            } catch (Exception e) {
                continue;
            }
            if (null != ywpdMember) {

                JSONObject attRoomInfo = new JSONObject();
                attRoomInfo.put("roomId", ywpdRoom.getRoomId());
                attRoomInfo.put("bacPicUrl", ywpdRoom.getBakPicUrl());
                attRoomInfo.put("roomName", ywpdRoom.getRoomName());
                attRoomInfo.put("attentionNum", ywpdRoom.getAttentionNum());
                attRoomInfo.put("liveStatus", ywpdRoom.getLiveStatus());
                attRoomInfo.put("roomType", ywpdRoom.getRoomType());
                attRoomInfo.put("nickName", ywpdMember.getNickName());
                attRoomInfo.put("imgUrl", ywpdMember.getImgUrl());

                data.add(attRoomInfo);
            }
        }

        data.sort(Comparator.comparingInt(o -> o.getInteger("liveStatus")));

        return data;
    }

    /**
     * 添加一个关注的房间
     */
    public void addAttRoom(long userId, long attuId) throws Exception {
        String attype = "room";
        String addTime = StringUtil.getDateTime();
        attentionService.addAttentionUser(userId, attuId, attype, addTime);
        YwpdRoom ywpdRoom = ywpdRoomService.selectRoomByRoomId(attuId);
        int attentionNum = ywpdRoom.getAttentionNum();
        attentionNum += 1;
        ywpdRoom.setAttentionNum(attentionNum);
        ywpdRoomService.updateRoom(ywpdRoom);
        log.info("用户{}关注房间{}成功。", userId, attuId);
    }

    /**
     * 取消关注房间，删除一个关注的房间
     *
     * @param userId userId
     * @param attuId 关注的房间号
     */
    public void deleteAttRoom(long userId, long attuId) throws Exception {
        attentionService.deleteAttentionUser(userId, attuId, "room");
        YwpdRoom ywpdRoom = ywpdRoomService.selectRoomByRoomId(attuId);
        int attentionNum = ywpdRoom.getAttentionNum();
        attentionNum -= 1;
        ywpdRoom.setAttentionNum(attentionNum);
        ywpdRoomService.updateRoom(ywpdRoom);
        log.info("用户{}取消关注房间{}成功", userId, attuId);
    }

    /**
     * 获取当前正在直播的房间接口，房间按照当前观众人数排序
     */
    public List getRoomPark(String roomType) {
        List<YwpdRoom> livingRoomsFromDb = new ArrayList<>();
        List<YwpdRoom> livingRooms = new ArrayList<>();

        try {
            livingRoomsFromDb = ywpdRoomService.selectLivingRoomByRoomType(roomType);

        } catch (Exception e) {
            e.printStackTrace();
            log.error("get living room failed,db operate failed");
        }

        for (YwpdRoom ywpdRoom : livingRoomsFromDb) {
            try {

                qiniu.getLiveStatus(ywpdRoom.getRoomId());
                livingRooms.add(ywpdRoom);
            } catch (Exception e) {
                log.info(ywpdRoom.getRoomId() + " 该房间上次异常退出，等待后台定时清理。");
            }
        }

        Map<Long, Integer> roomViewersNum = new LinkedHashMap<>();

        for (YwpdRoom room : livingRooms
        ) {
            //观众
            String roomViewer_redisKey = RoomUtils.get_roomViewer_redisKey(room.getRoomId());
            int viewersNum = (int) redisUtils.set_getSize(roomViewer_redisKey);
            roomViewersNum.put(room.getRoomId(), viewersNum);
        }

        List<Entry<Long, Integer>> list = new ArrayList<>(roomViewersNum.entrySet());

        ValueComparator valueComparator = new ValueComparator();

        list.sort(valueComparator);

        List<RoomRank> roomRange = new ArrayList<>();

        try {
            for (Entry<Long, Integer> longIntegerEntry : list) {
                long roomId = longIntegerEntry.getKey();
                RoomRank roomRank = new RoomRank();
                roomRank.setRoomId(roomId);
                roomRank.setGain(longIntegerEntry.getValue());

                YwpdRoom ywpdRoom = ywpdRoomService.selectRoomByRoomId(roomId);
                roomRank.setBakPicUrl(ywpdRoom.getBakPicUrl());
                roomRank.setRoomName(ywpdRoom.getRoomName());
                roomRank.setRoomType(ywpdRoom.getRoomType());

                long userId = ywpdRoom.getUserId();
                roomRank.setUserId(userId);

                YwpdMember ywpdMember = ywpdMemberService.selectYwpdMemberByUserId(userId);
                roomRank.setImgUrl(ywpdMember.getImgUrl());
                roomRank.setNickName(ywpdMember.getNickName());

                roomRange.add(roomRank);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return roomRange;
    }


    class Reward extends JSONObject {

        long userId;

        String nickName;

        String imgUrl;
    }

    /**
     * 创建一个房间
     */
    YwpdRoom createRoom(long userId) throws Exception {
        YwpdMember ywpdMember = ywpdMemberService.selectYwpdMemberByUserId(userId);

        YwpdRoom ywpdRoom = new YwpdRoom();
        long roomId = RoomUtils.generateShortUuid(8);
        ywpdRoom.setRoomId(roomId);
        ywpdRoom.setRoomName(ywpdMember.getNickName());
        ywpdRoom.setUserId(userId);
        ywpdRoom.setRoomNotice("该房间暂无公告");
        ywpdRoom.setLiveStatus(0);
        ywpdRoom.setCreatTime(StringUtil.getDateTime());

        //开始在七牛云创建直播流
        //初始化client
        Client cli = new Client(RoomConfig.ACCESS_KEY, RoomConfig.SECRET_KEY);
        //初始化Hub
        Hub hub = cli.newHub(RoomConfig.HUB);
        hub.create(roomId + "");

        //设置房间的推拉流地址
        ywpdRoom.setPullUrl(RoomConfig.getPullUrl(roomId));
        ywpdRoom.setPushUrl(RoomConfig.getPushUrl(roomId));

        ywpdRoomService.createYwpdRoom(ywpdRoom);

        return ywpdRoom;
    }

    /**
     * 获取我的房间信息
     */
    JSONObject getMyRoomInfo(long userId) throws Exception {
        YwpdMember ywpdMember = ywpdMemberService.selectYwpdMemberByUserId(userId);
        YwpdRoom ywpdRoom = ywpdRoomService.selectRoomByUserId(userId);
        JSONObject data = new JSONObject();

        //判断该用户是否已经拥有直播间
        if (null == ywpdRoom) {
            if (0 == ywpdMember.getRealNameAuth()) {
                data.put("realNameAuth", 0);
                return data;
            }
            ywpdRoom = createRoom(userId);
        }

        //判断该房间是否被永久禁播
        if (2 == ywpdRoom.getLiveStatus()) {
            data.put("liveStatus", 2);
            return data;
        }

        String allowRoomType = "fullVideo";
        //判断用户是否签约用户，签约用户拥有所有房间类型直播权，否则只有全屏直播类型权限
        if (1 == ywpdMember.getSign()) {
            //从redis中获取当前允许开启的直播类型
            String allowRoomType_redisKey = "roomType:allow";
            allowRoomType = redisUtils.string_get(allowRoomType_redisKey);
        }

        data.put("roomId", ywpdRoom.getRoomId());
        data.put("roomType", ywpdRoom.getRoomType());
        data.put("roomName", ywpdRoom.getRoomName());
        data.put("userId", ywpdRoom.getUserId());
        data.put("bakPicUrl", ywpdRoom.getBakPicUrl());
        data.put("pullUrl", ywpdRoom.getPullUrl());
        data.put("pushUrl", ywpdRoom.getPushUrl());
        data.put("liveStatus", ywpdRoom.getLiveStatus());
        data.put("roomNotice", ywpdRoom.getRoomNotice());
        data.put("allowRoomType", allowRoomType);

        return data;
    }

    /**
     * 通过userId获取个人信息，主要用在申请连麦的列表展示
     */
    public JSONObject getUserInfoByUserId(String userId) throws Exception {
        return getUserInfoByUserId(Long.parseLong(userId));
    }

    public JSONObject getUserInfoByUserId(long userId) throws Exception {
        YwpdMember ywpdMember = ywpdMemberService.selectYwpdMemberByUserId(userId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("nickName", ywpdMember.getNickName());
        jsonObject.put("imgUrl", ywpdMember.getImgUrl());
        return jsonObject;
    }

    /**
     * 初始化房间的redis数据
     */
    public void initRoom(long roomId, long userId) {
        clearRoomCache(roomId);
        //将主持人加入到观众列表中
        //redisAddViewers(roomId, userId);
    }

    /**
     * 申请连麦
     */
    public JSONObject apply(long roomId, String roomType, long userId) {
        JSONObject jsonObject = new JSONObject();
        String redisKey_applying = RoomUtils.get_applying_key(roomId);
        String redisKey_line = RoomUtils.get_line_key(roomId);
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);
        long size = redisUtils.list_getSize(redisKey_line);
        List lineUsers = redisUtils.list_range(redisKey_line);
        //判断已经连麦的人员是否已经满员
        if ("voice".equals(roomType) && size >= 8) {
            jsonObject.put("status", "full");
            return jsonObject;
        } else if ("video".equals(roomType) && size >= 3) {
            jsonObject.put("status", "full");
            return jsonObject;
        } else if (redisUtils.set_getMembers(redisKey_paipai).contains(userId + "")) {
            jsonObject.put("status", "inPaipai");
            return jsonObject;
        }

        //判断申请连麦的用户是否已经在连麦中
        if (lineUsers.contains(userId + "")) {
            jsonObject.put("status", "lining");
            return jsonObject;
        }

        //判断申请的用户是否已经在申请列表中,如果不在的话则添加进申请列表中
        List applyingUsers = redisUtils.list_range(redisKey_applying);
        if (!applyingUsers.contains(userId + "")) {
            redisUtils.list_rightPush(redisKey_applying, userId + "");
        }

        //构造返回值
        applyingUsers = redisUtils.list_range(redisKey_applying);
        jsonObject.put("status", "free");
        jsonObject.put("applyingUsers", applyingUsers);

        return jsonObject;
    }

    /**
     * 获取房间中正在申请连麦中的所有userId
     */
    public List getApplyingUsers(long roomId) {
        String redisKey = RoomUtils.get_applying_key(roomId);
        return redisUtils.list_range(redisKey);
    }

    /**
     * 房间连麦用户中添加一个申请连麦的用户，此时用户正在申请，主持人还未同意
     */
    public void addApplyingUser(long roomId, long userId) {
        String redisKey = RoomUtils.get_applying_key(roomId);
        redisUtils.list_rightPush(redisKey, userId + "");
    }

    /**
     * 删除一个申请连麦的用户，此时用户正在申请，被主持人拒绝后，从申请队列中删除掉
     */
    public void deleteApplyingUser(long roomId, long userId) {
        String redisKey = RoomUtils.get_applying_key(roomId);
        List list = redisUtils.list_range(redisKey);
        if (list.contains(userId + "")) {
            redisUtils.list_removeOne(redisKey, userId + "");
        }
    }


    /**
     * 申请连麦的人数变化，通知到前端的方法
     */
    public void applyLineChange(long roomId) {
        String redisKey = RoomUtils.get_applying_key(roomId);
        long applyLineCount = redisUtils.list_getSize(redisKey);
        Response msg = new Response();
        msg.setCode(ImCommand.LINE_APPLY_CHANGE);
        msg.setDesc("申请连麦人数变更通知");
        msg.setData((int) applyLineCount);
        Thread thread = new Thread(new ImSend(roomId + "", JSON.toJSONString(msg)));
        thread.start();
    }


    /**
     * 获取房间中正在连麦的所有userId
     */
    public List getLineUsers(long roomId) {
        String redisKey = RoomUtils.get_line_key(roomId);
        return redisUtils.list_range(redisKey);
    }


    /**
     * 房间连麦用户中添加一个连麦的用户，即主持人同意后，加入连麦集合。
     */
    public void addLineUser(long roomId, long userId) {
        String redisKey = RoomUtils.get_line_key(roomId);
        redisUtils.list_rightPush(redisKey, userId + "");
    }

    /**
     * 删除一个连麦中的用户
     */
    public void deleteLineUser(long roomId, long userId) {
        String redisKey = RoomUtils.get_line_key(roomId);
        List list = redisUtils.list_range(redisKey);
        if (list.contains(userId + "")) {
            redisUtils.list_removeOne(redisKey, userId + "");
        }
    }


    /**
     * 主持人下播，清除申请集合和连麦集合
     */
    public void clearRoomCache(long roomId) {
        String roomStatus_redisKey = RoomUtils.get_RoomStatus_RedisKey(roomId);
        String redisKey_applying = RoomUtils.get_applying_key(roomId);
        String redisKey_line = RoomUtils.get_line_key(roomId);
        String roomViewer_redisKey = RoomUtils.get_roomViewer_redisKey(roomId);
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);
        String redisKey_paipaiApplying = RoomUtils.get_paipaiApplying_key(roomId);
        String paipaiGift_redisKey = RoomUtils.get_paipaiGift_redisKey(roomId);
        String redisKey_baodeng = RoomUtils.get_baodeng_redisKey(roomId);
        String baodeng_countDown_redisKey = RoomUtils.get_baodeng_countDown_redisKey(roomId);
        String paipaiSend_redisKey = RoomUtils.get_paipaiSend_redisKey(roomId);
        String isRestartBaodeng_redisKey = RoomUtils.get_IsRestartBaodeng_redisKey(roomId);

        clearRoomRedis(roomStatus_redisKey);
        clearRoomRedis(redisKey_applying);
        clearRoomRedis(redisKey_line);
        clearRoomRedis(roomViewer_redisKey);
        clearRoomRedis(redisKey_paipai);
        clearRoomRedis(redisKey_paipaiApplying);
        clearRoomRedis(paipaiGift_redisKey);
        clearRoomRedis(redisKey_baodeng);
        clearRoomRedis(baodeng_countDown_redisKey);
        clearRoomRedis(isRestartBaodeng_redisKey);

        redisUtils.map_deleteKey(paipaiSend_redisKey);

        //将是否重新开始爆灯置为true，目的是结束当前正在爆灯的线程
        if ("false".equals(redisUtils.string_get(isRestartBaodeng_redisKey))) {
            redisUtils.string_set(isRestartBaodeng_redisKey, "true");
            try {
                //睡眠1.5秒，因为爆灯线程中有1秒的时间来监测是否重新开始了
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public void clearRoomRedis(String redisKey) {
        if (redisUtils.hasKey(redisKey)) {
            redisUtils.string_delete(redisKey);
        }
    }

    /**
     * 观众退出直播间，则删除掉该房间的申请列表和连麦列表中的该用户。
     */
    public void deleteApplyAndLineUser(long roomId, long userId) {
        String redisKey_applying = RoomUtils.get_applying_key(roomId);//申请连麦key
        String redisKey_line = RoomUtils.get_line_key(roomId);//连麦key
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);//拍拍位 key
        String redisKey_paipaiApplying = RoomUtils.get_paipaiApplying_key(roomId);//申请拍拍 key
        String paipaiSend_redisKey = RoomUtils.get_paipaiSend_redisKey(roomId);//申请拍拍赠送 key
        String paipaiGift_redisKey = RoomUtils.get_paipaiGift_redisKey(roomId);//申请拍拍礼物 key
        String redisKey_baodeng = RoomUtils.get_baodeng_redisKey(roomId);//爆灯 key

        redisUtils.list_removeOne(redisKey_applying, userId + "");//如果正在申请连麦，则删掉自己
        redisUtils.list_removeOne(redisKey_line, userId + "");//如果正在连麦位，则删掉自己

        //如果该用户是拍拍位的
        if (redisUtils.set_getMembers(redisKey_paipai).contains(userId + "")) {
            redisUtils.string_delete(paipaiGift_redisKey); //清除拍拍礼物
            redisUtils.string_delete(redisKey_paipai);//清除拍拍位
            redisUtils.string_delete(redisKey_baodeng);//清除爆灯
            redisUtils.string_delete(redisKey_line);//清除连麦位所有人

            redisUtils.map_deleteKey(paipaiSend_redisKey);//清除掉拍拍赠送记录
        }

        if (redisUtils.set_getMembers(redisKey_paipaiApplying).contains(userId + "")) {
            redisUtils.set_remove(redisKey_paipaiApplying, userId + "");
        }

        if (null != redisUtils.map_getOneValue(paipaiSend_redisKey, userId + "")) {
            redisUtils.map_deleteOne(paipaiSend_redisKey, userId + "");
        }

    }

    /**
     * 申请拍拍
     */
    public JSONObject applyPaipai(String roomType, long roomId, long userId) throws Exception {
        JSONObject jsonObject = new JSONObject();

//        YwpdRoom ywpdRoom = ywpdRoomService.selectRoomByRoomId(roomId);
//        long toUserId = ywpdRoom.getUserId();
//        long fromUserId = userId;
//        int sendCount = giftSendCount(toUserId, fromUserId);
//
//        //如果是 video 房间类型，则判断该用户是否给送够礼物，送礼必须达到要求的虚拟币才可以。
//        if ("video".equals(roomType) && sendCount < 100) {
//            jsonObject.put("status", "noPermission");
//            return jsonObject;
//        }

        //判断当前房间中拍拍中是否已经有人
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);
        if (redisUtils.hasKey(redisKey_paipai)) {
            jsonObject.put("status", "full");
            return jsonObject;
        }

        //判断申请的观众是不是已经在申请队列中
        String redisKey_paipaiApplying = RoomUtils.get_paipaiApplying_key(roomId);
        if (redisUtils.set_getMembers(redisKey_paipaiApplying).contains(userId + "")) {
            jsonObject.put("status", "applying");
            return jsonObject;
        }

        //如果条件都满足，则通过申请，将该用户添加到申请中的列表中
        redisUtils.set_add(redisKey_paipaiApplying, userId + "");
        Set<String> paipaiApplyingUsers = redisUtils.set_getMembers(redisKey_paipaiApplying);
        jsonObject.put("status", "free");
        jsonObject.put("paipaiApplyingUsers", paipaiApplyingUsers);

        return jsonObject;

    }

    /**
     * 删除一个申请拍拍的用户
     */
    public void deletePaipaiApplyingUser(long roomId, long applyUserId) {
        String redisKey_paipaiApplying = RoomUtils.get_paipaiApplying_key(roomId);
        redisUtils.set_remove(redisKey_paipaiApplying, applyUserId + "");
    }


    /**
     * 申请拍拍的人数变化，需要通知到前端
     */
    public void applyPaipaiChange(long roomId) {
        String redisKey_paipaiApplying = RoomUtils.get_paipaiApplying_key(roomId);
        long applyPaipaiCount = redisUtils.set_getSize(redisKey_paipaiApplying);
        Response msg = new Response();
        msg.setCode(ImCommand.PAIPAI_APPLY_CHANGE);
        msg.setDesc("申请拍拍人数变更通知");
        msg.setData((int) applyPaipaiCount);
        Thread thread = new Thread(new ImSend(roomId + "", JSON.toJSONString(msg)));
        thread.start();
    }

    /*
        获取当前正在拍拍的用户
     */
    public String getPaipaiUsers(long roomId) {
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);
        if (!redisUtils.hasKey(redisKey_paipai)) {
            return null;
        }
        return redisUtils.set_getMembers(redisKey_paipai).toArray()[0].toString();
    }


    /**
     * 获取当前正在申请拍拍的用户列表
     */
    public Set getPaipaiApplyingUsers(long roomId) {
        String redisKey_paipaiApplying = RoomUtils.get_paipaiApplying_key(roomId);
        return redisUtils.set_getMembers(redisKey_paipaiApplying);
    }

    /**
     * 添加拍拍用户
     */
    public void addPaipaiUser(long roomId, long applyUserId) {
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);
        long l = redisUtils.set_getSize(redisKey_paipai);
        if (l >= 1) {
            return;
        }
        redisUtils.set_add(redisKey_paipai, applyUserId + "");
    }

    /**
     * 删除拍拍用户
     */
    public void deletePaipaiUser(long roomId, long deleteUserId) {
        String redisKey_paipai = RoomUtils.get_paipai_key(roomId);
        redisUtils.string_delete(redisKey_paipai);
        String paipaiGift_redisKey = RoomUtils.get_paipaiGift_redisKey(roomId);
        if (redisUtils.hasKey(paipaiGift_redisKey)) {
            redisUtils.string_delete(paipaiGift_redisKey);
        }
        String baodeng_countDown_redisKey = RoomUtils.get_baodeng_countDown_redisKey(roomId);
        String paipaiSend_redisKey = RoomUtils.get_paipaiSend_redisKey(roomId);
        String paipaiApplying_key = RoomUtils.get_paipaiApplying_key(roomId);
        redisUtils.map_deleteKey(baodeng_countDown_redisKey);
        redisUtils.map_deleteKey(paipaiSend_redisKey);
        redisUtils.map_deleteKey(paipaiApplying_key);
    }

    /**
     * 将拍拍礼物赠送存在redis中
     */
    public void setPaipaiSend(long roomId, long fromUserId, int spendCoin) {
        String paipaiSend_redisKey = RoomUtils.get_paipaiSend_redisKey(roomId);
        int paipaiSend = getPaipaiSend(roomId, fromUserId);
        redisUtils.map_put(paipaiSend_redisKey, fromUserId + "", spendCoin * 10 + paipaiSend);
    }

    /**
     * 获取某个观众拍拍房间中赠送礼物的值
     */
    public int getPaipaiSend(long roomId, long fromUserId) {
        return getPaipaiSend(roomId, fromUserId + "");
    }

    public int getPaipaiSend(long roomId, String fromUserId) {
        String paipaiSend_redisKey = RoomUtils.get_paipaiSend_redisKey(roomId);
        Object o = redisUtils.map_getOneValue(paipaiSend_redisKey, fromUserId);
        if (null == o) {
            return 0;
        }
        return (Integer) o;
    }

    //获取房间内正在拍拍的连麦位的用户信息
//    public JSONObject getPaipaiLineInfo(){
//
//    }

    /**
     * 获取拍拍房间中应该连麦的用户列表。
     */
    public List<String> getPaipaiLine(long roomId) {
        List<String> userIds = new ArrayList<>();
        String paipaiSend_redisKey = RoomUtils.get_paipaiSend_redisKey(roomId);
        Map map = redisUtils.map_getAll(paipaiSend_redisKey);
        Map paipaiSendMap = StringUtil.mapSortByValue(map);
        Set set = paipaiSendMap.keySet();
        for (Object o : set) {
            userIds.add(String.valueOf(o));
        }
        if (userIds.size() >= 3) {
            return userIds.subList(0, 3);
        }
        return userIds;
    }

    /**
     * 计算fromUserId给UserId送的礼物总值（虚拟货币值）
     *
     * @return int
     */
    public int giftSendCount(long toUserId, long fromUserId) throws Exception {
        List<GiftSend> giftSends = giftSendService
            .selectByUserIdAndFromUserId(toUserId, fromUserId);
        int sendCount = 0;
        for (GiftSend giftSend : giftSends
        ) {
            sendCount += giftSend.getGiftNum() * giftSend.getNeedCoin();
        }

        return sendCount;
    }

    /**
     * 设置拍拍的礼物要求，即最低标准
     */
    public void setPaipaiGift(long roomId, int giftId) {
        String paipaiGift_redisKey = RoomUtils.get_paipaiGift_redisKey(roomId);
        redisUtils.string_set(paipaiGift_redisKey, giftId + "");
    }

    /*
     *获取拍拍要求的最低要求礼物
     */
    public Gift getPaipaiGift(long roomId) {
        String paipaiGift_redisKey = RoomUtils.get_paipaiGift_redisKey(roomId);
        int giftId = Integer.parseInt(redisUtils.string_get(paipaiGift_redisKey));
        Gift gift = null;
        try {
            gift = giftService.selectByPrimaryKey(giftId);
        } catch (Exception e) {
            log.error("获取礼物失败，数据库操作失败");
        }
        return gift;
    }

    /**
     * 获取拍拍允许的礼物列表
     */
    public List<Gift> getPaipaiGifts(long roomId) {
        String paipaiGift_redisKey = RoomUtils.get_paipaiGift_redisKey(roomId);

        if (!redisUtils.hasKey(paipaiGift_redisKey)) {
            return null;
        }
        int giftId = Integer.parseInt(redisUtils.string_get(paipaiGift_redisKey));
        Gift giftNeed = null;
        int needCoin = 0;
        List<Gift> giftList = null;

        try {
            giftNeed = giftService.selectByPrimaryKey(giftId);
            needCoin = giftNeed.getNeedCoin();
            giftList = giftService.selectAllEnableGift();

        } catch (Exception e) {
            log.error("获取礼物列表失败，数据库操作失败");
        }

        List<Gift> paipaiGifts = new ArrayList<>();

        for (Gift gift : giftList) {
            if (gift.getNeedCoin() >= needCoin) {
                if (gift.getId() != giftId) {
                    paipaiGifts.add(gift);
                }
            }
        }

        //将低价礼物放到第一个位置。
        paipaiGifts.add(0, giftNeed);
        return paipaiGifts;
    }

    //初始化拍拍房间爆灯的记录
    public void initBaodeng(long roomId) {
        String redisKey_baodeng = RoomUtils.get_baodeng_redisKey(roomId);
        if (redisUtils.hasKey(redisKey_baodeng)) {
            redisUtils.string_delete(redisKey_baodeng);
        }
        redisUtils.string_set(redisKey_baodeng, "0");
    }

    //设置爆灯的记录,并返回当前爆灯值。爆灯：即该房间内所送礼物的虚拟货币值达到了多少。
    public int setBaodengValue(long roomId, int coin) {
        String redisKey_baodeng = RoomUtils.get_baodeng_redisKey(roomId);
        int baodeng = 0;
        if (redisUtils.hasKey(redisKey_baodeng)) {
            baodeng = Integer.parseInt(redisUtils.string_get(redisKey_baodeng));
        }
        baodeng += coin;
        redisUtils.string_set(redisKey_baodeng, baodeng + "");
        return baodeng;
    }

    //获取当前房间的爆灯值
    public int getBaodengValue(long roomId) {
        String redisKey_baodeng = RoomUtils.get_baodeng_redisKey(roomId);
        return Integer.parseInt(redisUtils.string_get(redisKey_baodeng));
    }

    //房间爆灯开始
    public void startBaodeng(long roomId) {
        restartBaodeng(roomId);
        setBaodengCountDown(roomId + "", 180);
        Thread thread = new Thread(new Baodeng(roomId + ""));
        thread.start();
    }

    /**
     * 爆灯倒计时写进redis
     */
    public void setBaodengCountDown(String roomId, int countDown) {
        String baodeng_countDown_redisKey = RoomUtils.get_baodeng_countDown_redisKey(roomId);
        redisUtils.string_set(baodeng_countDown_redisKey, countDown + "");
    }

    /**
     * 设置一个房间是否重新开始爆灯的标识
     */
    public void restartBaodeng(long roomId) {
        String isRestartBaodeng_redisKey = RoomUtils.get_IsRestartBaodeng_redisKey(roomId);
        redisUtils.string_set(isRestartBaodeng_redisKey, "true");
    }

    /**
     * 将房间是否爆灯设置为false，字符串类型，非bool类型
     */
    public void setRestartBaodengFalse(long roomId) {
        String isRestartBaodeng_redisKey = RoomUtils.get_IsRestartBaodeng_redisKey(roomId);
        redisUtils.string_set(isRestartBaodeng_redisKey, "false");
    }

    public void setRestartBaodengFalse(String roomId) {
        String isRestartBaodeng_redisKey = RoomUtils.get_IsRestartBaodeng_redisKey(roomId);
        redisUtils.string_set(isRestartBaodeng_redisKey, "false");
    }

    /**
     * 从redis中获取爆灯倒计时
     */
    public int getBaodengCountDown(long roomId) {
        String baodeng_countDown_redisKey = RoomUtils.get_baodeng_countDown_redisKey(roomId);
        if (!redisUtils.hasKey(baodeng_countDown_redisKey)) {
            return -1;
        }
        return Integer.parseInt(redisUtils.string_get(baodeng_countDown_redisKey));
    }

    public int getBaodengCountDown(String roomId) {
        long roomId_long = Long.parseLong(roomId);
        return getBaodengCountDown(roomId_long);
    }

    /**
     * 获取当前房间内的所有观众列表
     */
    public Set<String> getRoomViewers(long roomId) {
        return getRoomViewers(roomId + "");
    }

    public Set<String> getRoomViewers(String roomId) {
        String roomViewer_redisKey = RoomUtils.get_roomViewer_redisKey(roomId);
        return redisUtils.set_getMembers(roomViewer_redisKey);
    }

    /**
     * 房间人数变化，通知到房间
     */
    public void viewersChange(long roomId) {
        viewersChange(roomId + "");
    }

    public void viewersChange(String roomId) {
        long viewersNum = redisUtils.set_getSize(RoomUtils.get_roomViewer_redisKey(roomId));
        Response msg = new Response();
        msg.setCode(ImCommand.VIEWERS_CHANGE);
        msg.setDesc("房间人数变化");
        msg.setData((int) viewersNum);
        Thread thread = new Thread(new ImSend(roomId, JSON.toJSONString(msg)));
        thread.start();
    }

    /**
     * 房间火力值增加方法
     */
    public void addFire(long roomId, int spendCoin) {
        int fire = getFire(roomId);
        fire += (spendCoin * 10);
        setFire(roomId, fire);
        fireChange(roomId);
    }

    /**
     * 设置当前房间的火力值
     */
    public void setFire(long roomId, int fire) {
        setFire(roomId + "", fire);
    }

    public void setFire(String roomId, int fire) {
        String fire_redisKey = RoomUtils.get_fire_redisKey(roomId);
        redisUtils.string_set(fire_redisKey, fire + "");
    }

    /**
     * 获取当前房间的火力值
     */
    public int getFire(long roomId) {
        return getFire(roomId + "");
    }

    public int getFire(String roomId) {
        String fire_redisKey = RoomUtils.get_fire_redisKey(roomId);
        int fire;
        if (redisUtils.hasKey(fire_redisKey)) {
            fire = Integer.parseInt(redisUtils.string_get(fire_redisKey));
        } else {
            fire = 0;
        }
        return fire;
    }

    /**
     * 房间火力值变化，通知到房间，火力值解释：即该房间中送礼的价值总额
     */
    public void fireChange(long roomId) {
        fireChange(roomId + "");
    }

    public void fireChange(String roomId) {
        int fire = getFire(roomId);
        Response msg = new Response();
        msg.setCode(ImCommand.FIRE_CHANGE);
        msg.setDesc("房间火力值变化");
        msg.setData(fire);
        Thread thread = new Thread(new ImSend(roomId, JSON.toJSONString(msg)));
        thread.start();
    }

    //当赠送了贵重礼物的时候，通知到房间
    public void valuableGiftSend(long toUserId, long fromUserId, int giftId) {
        YwpdMember toMem = null;
        YwpdMember fromMem = null;
        Gift gift = null;
        try {
            toMem = ywpdMemberService.selectYwpdMemberByUserId(toUserId);
            fromMem = ywpdMemberService.selectYwpdMemberByUserId(fromUserId);
            gift = giftService.selectByPrimaryKey(giftId);
        } catch (Exception e) {
            log.error("获取礼物打赏信息失败。");
            return;
        }

        JSONObject data = new JSONObject();
        if (fromMem != null && toMem != null && gift != null) {
            data.put("fromNickName", fromMem.getNickName());
            data.put("fromImgUrl", fromMem.getImgUrl());
            data.put("toNickName", toMem.getNickName());
            data.put("toImgUrl", toMem.getImgUrl());
            data.put("giftName", gift.getGiftName());
            data.put("giftIcon", gift.getGiftIcon());

            Response msg = new Response();
            msg.setCode(ImCommand.VALUEABLE_GIFT_SEND);
            msg.setDesc("贵重礼物赠送通知");
            msg.setData(data.toJSONString());

            List<Long> roomIdList = ywpdRoomService.selectAllLivingRoomId();
            for (Long roomId : roomIdList) {
                Thread thread = new Thread(new ImSend(roomId + "", JSON.toJSONString(msg)));
                thread.start();
            }
        }


    }

    //按照value排序的比较类
    private static class ValueComparator implements Comparator<Entry<Long, Integer>> {

        @Override
        public int compare(Entry<Long, Integer> m, Entry<Long, Integer> n) {
            return n.getValue() - m.getValue();
        }
    }

    //内部类，这里专门用来出发多线程，触发爆灯后，由后台给前台发消息，并记录爆灯剩余时间。
    class Baodeng implements Runnable {

        String roomId;
        Random random;

        Baodeng(String roomId) {
            this.roomId = roomId;
            random = new Random();
        }

        @SneakyThrows
        public void run() {

            String isRestartBaodeng_redisKey = RoomUtils.get_IsRestartBaodeng_redisKey(roomId);
            tencentImRealization.sendGroupMsg(startBaodengMsg());
            Thread.sleep(3000);
            //开始爆灯倒计时之前，先将重新开始的标识置为false
            if ("true".equals(redisUtils.string_get(isRestartBaodeng_redisKey))) {
                setRestartBaodengFalse(roomId);
            }
            int baodengCountDown = getBaodengCountDown(roomId);
            for (int i = baodengCountDown; i >= 0; i--) {
                String isRestartBaodeng = redisUtils.string_get(isRestartBaodeng_redisKey);
                //在倒计时的过程中，需要判断是否新开了线程将重新倒计时置为了true
                if ("true".equals(isRestartBaodeng)) {
                    break;
                }
                setBaodengCountDown(roomId, i);
                Thread.sleep(1000);
            }
        }

        /**
         * 生成爆灯指令
         */
        JSONObject startBaodengMsg() {
            Response msg = new Response();
            msg.setCode(ImCommand.BAODENG);
            msg.setDesc("3秒后开始爆灯");
            return tencentImRealization.generateImBody(JSON.toJSONString(msg), roomId);
        }

        /**
         * 爆灯倒计时写进redis
         */
        void setBaodengCountDown(String roomId, int countDown) {
            String baodeng_countDown_redisKey = RoomUtils.get_baodeng_countDown_redisKey(roomId);
            redisUtils.string_set(baodeng_countDown_redisKey, countDown + "");
        }

    }

    //内部类，主要用来触发多线程，给房间发送指令
    class ImSend implements Runnable {

        String roomId;
        String msg;

        ImSend(String roomId, String msg) {
            this.roomId = roomId;
            this.msg = msg;
        }

        @SneakyThrows
        @Override
        public void run() {
            JSONObject imBody = tencentImRealization.generateImBody(msg, roomId);
            Thread.sleep(500);
            tencentImRealization.sendGroupMsg(imBody);
        }
    }

}
